package com.common.sevice.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.common.exception.ErrorException;
import com.common.groovy.model.DataModel;
import com.common.model.SystemApplicationModel;
import com.common.model.SystemApplicationServiceModel;
import com.common.model.SystemApplicationWebModel;
import com.common.mysql.Where;
import com.common.progress.ProgressManager;
import com.common.sevice.SystemApplicationModelService;
import com.common.sevice.SystemApplicationService;
import com.common.sevice.SystemApplicationWebService;
import com.common.sevice.SystemImageService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Date: 2025/7/28 13:45
 */
@Service
public class SystemImageServiceImpl implements SystemImageService {

    @Autowired
    private SystemApplicationModelService systemApplicationModelService;

    @Autowired
    private SystemApplicationService systemApplicationService;

    @Autowired
    private SystemApplicationWebService systemApplicationWebService;

    //不配置该值，则默认存放到docker文件夹下
    @Value("${docker.imageUrl:/docker/}")
    private String dockerImageUrl;

    @Value("${docker.java.url:http://host.docker.internal:12000/v1/docker-java/buildImage}")
    private String dockerJavaUrl;

    @Override
    public String generaImage(Map<String, Object> params, SystemApplicationModel applicationModel) {
        String appId = (String) params.get("appId");
        Object saveUrl = params.get("saveUrl");
        List<Map<String, Object>> data = (List<Map<String, Object>>) params.get("data");
        String name = applicationModel.getName();//名称
        String userName = applicationModel.getUserName();//用户名
        String userDir = System.getProperty("user.dir");//当前文件所属位置
        ProgressManager progressManager = ProgressManager.getInstance();
        progressManager.registerProgressBar(appId, 15);
        Map<String, Map<String, Object>> paramsData = new HashMap<>();
        if (!CollectionUtils.isEmpty(data)) {
            paramsData = data.stream()
                    .collect(Collectors.toMap(map -> (String) map.get("code"), map ->(Map<String, Object>) map.get("value")));
        }

        //查询当前应用id所对应的所有相关的脚本
        //第一步。构建sql建表脚本
        progressManager.updateProgress(appId);
        String businessTableSql = createBusinessTableSql(appId);
        String ddmSql = createDdmSql(appId);
        if (paramsData.containsKey("mysql")) {
            Map<String, Object> mysql = paramsData.get("mysql");
            mysql.put("businessTableSql", businessTableSql);
            mysql.put("ddmSql", ddmSql);
            mysql.put("dockerfileType","mysql");
            buildResponse(HttpUtil.createPost(dockerJavaUrl).body(JSONUtil.parseObj(mysql).toString(), MediaType.APPLICATION_JSON_VALUE).execute());
        }


        //第二步，构建docker-java镜像
        progressManager.updateProgress(appId);
        if (paramsData.containsKey("dockerJava")) {
            Map<String, Object> dockerJava = paramsData.get("dockerJava");
            dockerJava.put("dockerfileType", "docker-java");
            buildResponse(HttpUtil.createPost(dockerJavaUrl).body(JSONUtil.parseObj(dockerJava).toString(), MediaType.APPLICATION_JSON_VALUE).execute());
        }

        //第三步，构建web低代码生成前端
        progressManager.updateProgress(appId);
        if (paramsData.containsKey("generate")) {
            Map<String, Object> generate = paramsData.get("generate");
            generate.put("dockerfileType", "generate");
            buildResponse(HttpUtil.createPost(dockerJavaUrl).body(JSONUtil.parseObj(generate).toString(), MediaType.APPLICATION_JSON_VALUE).execute());
        }
        //第四步，构建web结果生成前端
        progressManager.updateProgress(appId);
        if (paramsData.containsKey("outcome")) {
            Map<String, Object> outcome = paramsData.get("outcome");
            outcome.put("dockerfileType", "outcome");
            buildResponse(HttpUtil.createPost(dockerJavaUrl).body(JSONUtil.parseObj(outcome).toString(), MediaType.APPLICATION_JSON_VALUE).execute());
        }
        //第五步，构建service结果服务
        progressManager.updateProgress(appId);
        if (paramsData.containsKey("business")) {
            Map<String, Object> business = paramsData.get("business");
            business.put("dockerfileType", "business");
            business.put("APPID", appId);
            buildResponse(HttpUtil.createPost(dockerJavaUrl).body(JSONUtil.parseObj(business).toString(), MediaType.APPLICATION_JSON_VALUE).execute());
        }
//
//        //顶层目录名称
//        String topDirName = new StringBuffer(dockerImageUrl).append(name).append("_").append(userName).toString();
//        File topDir = FileUtil.mkdir(topDirName);
//        //如果存在该文件夹，则直接删除里面所有数据，重新生成
//        if (!FileUtil.isDirEmpty(topDir)) {
//            FileUtil.del(topDir);
//        }
//        topDir = FileUtil.mkdir(topDirName);
//
//        //mysql镜像处理
//        //生成sql初始化脚本
//
//        FileUtil.copy(userDir + "/docker/mysql8/dockerfile", new StringBuffer(topDirName).append("/mysql8/dockerfile").toString(), true);
//        File mysql8Env = FileUtil.file(new StringBuffer(topDirName).append("/mysql8").toString(), ".env");
//        List<String> mysql8EnvContentList = Arrays.asList("MYSQL_ROOT_PASSWORD=root");
//        FileUtil.writeLines(mysql8EnvContentList, mysql8Env, Charset.defaultCharset());
//        //生成docker-compose脚本
//        //低代码前台页
//        //结果程序前台页
//        //后端服务
//        //nginx容器
//        //文件服务

        //docker-compose 命令行
        return new StringBuffer("docker compose")
                .append(" -f ").append(saveUrl).append("/docker-compose.yaml")
                .append(" -p ").append(appId)
                .append(" up -d")
                .toString();
    }

    /**
     * 构建结果
     * @param result
     */
    private void buildResponse(HttpResponse result) {
        JSONObject resultJsonObject = JSONUtil.parseObj(result.body());
        String code = resultJsonObject.getStr("code");
        if ("200".equals(code)){
            // TODO: 2025/8/5 构建结果
        }
    }

    public String createDdmSql(String appId) {
        StringBuffer result = new StringBuffer();
        result.append("INSERT INTO `system_user` (`id`, `account`, `password`, `username`, `create_by`, `update_by`, `create_time`, `update_time`, `del_flag`, `remarks`) VALUES ('1', 'admin', '666666', '系统管理员', NULL, NULL, NULL, NULL, '0', NULL);\n");

        List<SystemApplicationModel> applicationModelList = systemApplicationService.search(Where.build().field("id").equal(appId)
                .and().field("del_flag").equal(0));
        List<String> appList = new LinkedList<>();
        for (SystemApplicationModel applicationModel : applicationModelList) {
            List<String> appValueList = new LinkedList<>();
            appValueList.add(convertStr(applicationModel.getId()));
            appValueList.add(convertStr(applicationModel.getName()));
            appValueList.add(convertStr(applicationModel.getUserName()));
            appValueList.add(convertStr(applicationModel.getDelFlag()));
            appValueList.add(convertStr(applicationModel.getCreateTime()));
            appValueList.add(convertStr(applicationModel.getUpdateTime()));
            appValueList.add(convertStr(applicationModel.getCreateBy()));
            appValueList.add(convertStr(applicationModel.getUpdateBy()));
            appValueList.add(convertStr(applicationModel.getRemarks()));
            appList.add(new StringBuffer("(").append(String.join(",",appValueList)).append(")").toString());
        }

        if (!CollectionUtils.isEmpty(appList)){
            result.append("INSERT INTO `system_application` (`id`, `name`, `user_name`, `del_flag`, `create_time`, `update_time`, `create_by`, `update_by`, `remarks`) VALUES");
            result.append(String.join(",", appList)).append(";\n");
        }

        List<SystemApplicationServiceModel> serviceModelList = systemApplicationModelService.search(Where.build().field("app_id").equal(appId)
                .and().field("del_flag").equal(0));
        List<String> modelList = new LinkedList<>();
        for (SystemApplicationServiceModel serviceModel : serviceModelList) {
            List<String> modelValueList = new LinkedList<>();
            modelValueList.add(convertStr(serviceModel.getId()));
            modelValueList.add(convertStr(serviceModel.getParentId()));
            modelValueList.add(convertStr(serviceModel.getAppId()));
            modelValueList.add(convertStr(serviceModel.getData()));
            modelValueList.add(convertStr(serviceModel.getType()));
            modelValueList.add(convertStr(serviceModel.getName()));
            modelValueList.add(convertStr(serviceModel.getCreateTime()));
            modelValueList.add(convertStr(serviceModel.getUpdateTime()));
            modelValueList.add(convertStr(serviceModel.getDelFlag()));
            modelValueList.add(convertStr(serviceModel.getCreateBy()));
            modelValueList.add(convertStr(serviceModel.getUpdateBy()));
            modelValueList.add(convertStr(serviceModel.getRemarks()));
            modelValueList.add(convertStr(serviceModel.getSort()));
            modelValueList.add(convertStr(serviceModel.getExtra()));
            modelList.add(new StringBuffer("(").append(String.join(",", modelValueList)).append(")").toString());
        }
        if (!CollectionUtils.isEmpty(modelList)){
            result.append("INSERT INTO `system_application_service` (`id`, `parent_id`, `app_id`, `data`, `type`, `name`, `create_time`, `update_time`, `del_flag`, `create_by`, `update_by`, `remarks`, `sort`, `extra`) VALUES");
            result.append(String.join(",", modelList)).append(";\n");
        }

        List<SystemApplicationWebModel> applicationWebModelList = systemApplicationWebService.search(Where.build().field("app_id").equal(appId)
                .and().field("del_flag").equal(0));
        List<String> webList = new LinkedList<>();
        for (SystemApplicationWebModel webModel : applicationWebModelList) {
            List<String> webValueList = new LinkedList<>();
            webValueList.add(convertStr(webModel.getId()));
            webValueList.add(convertStr(webModel.getParentId()));
            webValueList.add(convertStr(webModel.getAppId()));
            webValueList.add(convertStr(webModel.getData()));
            webValueList.add(convertStr(webModel.getType()));
            webValueList.add(convertStr(webModel.getLabel()));
            webValueList.add(convertStr(webModel.getCode()));
            webValueList.add(convertStr(webModel.getIcon()));
            webValueList.add(convertStr(webModel.getCreateTime()));
            webValueList.add(convertStr(webModel.getUpdateTime()));
            webValueList.add(convertStr(webModel.getDelFlag()));
            webValueList.add(convertStr(webModel.getCreateBy()));
            webValueList.add(convertStr(webModel.getUpdateBy()));
            webValueList.add(convertStr(webModel.getRemarks()));
            webValueList.add(convertStr(webModel.getSort()));
            webValueList.add(convertStr(webModel.getExtra()));
            webList.add(new StringBuffer("(").append(String.join(",", webValueList)).append(")").toString());
        }
        if (!CollectionUtils.isEmpty(webList)){
            result.append("INSERT INTO `system_application_web` (`id`, `parent_id`, `app_id`, `data`, `type`, `label`, `code`, `icon`, `create_time`, `update_time`, `del_flag`, `create_by`, `update_by`, `remarks`, `sort`, `extra`) VALUES");
            result.append(String.join(",", webList)).append(";\n");
        }
        return result.toString();
    }

    private String convertStr(Object content) {
        if (!ObjectUtils.isEmpty(content)){
            if (JSONUtil.isTypeJSONObject(String.valueOf(content))){
                return new StringBuffer("'").append(JSONUtil.parseObj(content).toString().replace("\\", "\\\\")
                        .replace("\"", "\\\"")
                        .replace("'", "\\'")
                        .replace("\n", "\\n")
                        .replace("\r", "\\r")
                        .replace("\t", "\\t")).append("'").toString();
            }else if (JSONUtil.isTypeJSONArray(String.valueOf(content))){
                return new StringBuffer("'").append(JSONUtil.parseArray(content).toString().replace("\\", "\\\\")
                        .replace("\"", "\\\"")
                        .replace("'", "\\'")
                        .replace("\n", "\\n")
                        .replace("\r", "\\r")
                        .replace("\t", "\\t")).append("'").toString();
            }
            return new StringBuffer("'").append((String.valueOf(content)).replace("\\", "\\\\")
                    .replace("\"", "\\\"")
                    .replace("'", "\\'")
                    .replace("\n", "\\n")
                    .replace("\r", "\\r")
                    .replace("\t", "\\t")).append("'").toString();
        }
        return "NULL";
    }

    public String createBusinessTableSql(String appId) {
        List<SystemApplicationServiceModel> modelList = systemApplicationModelService.search(Where.build().field("app_id").equal(appId)
                .and().field("del_flag").equal(0)
                .and().field("type").equal(3));
        StringBuffer result = new StringBuffer();
        for (SystemApplicationServiceModel applicationServiceModel : modelList) {
            JSONObject data = applicationServiceModel.getData();
            DataModel dataModel = data.toBean(DataModel.class);
            DataModel.Table table = dataModel.getTable();
            StringBuffer sql = new StringBuffer("CREATE TABLE `");
            if (ObjectUtils.isEmpty(table)){
                throw new ErrorException("表信息不能为空");
            }
            sql.append(table.getName()).append("`( \n");
            List<DataModel.Field> fieldList = dataModel.getField();
            List<String> primaryKeyList = new LinkedList<>();
            for (DataModel.Field field : fieldList) {
                if (field.getPrimaryKey()){
                    primaryKeyList.add(field.getName());
                }
                sql.append("`").append(field.getName()).append("` ");
                String fieldType = field.getType();
                if ("varchar".equals(fieldType) || "char".equals(fieldType)){
                    sql.append(fieldType).append("(").append(field.getMaxLength()).append(")");
                    sql.append(" CHARACTER SET ").append(field.getCharset());
                    sql.append(" COLLATE ").append(field.getCollate());
                }else if("decimal".equals(fieldType)){
                    sql.append(fieldType).append("(").append(field.getMaxLength()).append(",").append(field.getDecimalDigits()).append(")");
                } else {
                    sql.append(fieldType);
                }
                if (!ObjectUtils.isEmpty(field.getRequired()) && field.getRequired()){
                    sql.append(" NOT NULL ");
                }
                if (StringUtils.hasText(field.getDefaultValue())) {
                    sql.append(" DEFAULT ").append(field.getDefaultValue());
                } else if (ObjectUtils.isEmpty(field.getRequired()) || !field.getRequired()) {
                    sql.append(" DEFAULT NULL ");
                }
                if (!ObjectUtils.isEmpty(field.getUpdateByCurrentTime()) && field.getUpdateByCurrentTime()){
                    sql.append(" ON UPDATE CURRENT_TIMESTAMP ");
                }
                if (StringUtils.hasText(field.getComment())){
                    sql.append(" COMMENT '").append(field.getComment()).append("'");
                }
                sql.append(",\n");
            }

            if (!CollectionUtils.isEmpty(primaryKeyList)){
                sql.append("PRIMARY KEY (");
                String join = String.join(",", primaryKeyList.stream()
                        .map(s -> "`" + s + "`")
                        .collect(Collectors.toList()));
                sql.append(join).append(")  USING BTREE \n");
            }
            sql.append(") ENGINE=").append(table.getEngine()).append(" DEFAULT CHARSET=").append(table.getCharset()).append(" COLLATE=").append(table.getCollate()).append(";\n");
            result.append(sql);
        }
        return result.toString();
    }
}
